using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.Design.Serialization;
using System.CodeDom;
using System.ComponentModel;
using System.Windows.Forms;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Collections;

namespace XnaDesignerGenerator
{
    public class XnaGameComponentGenerator : CodeDomSerializer
    {
        public override object Serialize(IDesignerSerializationManager manager, object value)
        {
            //base.Serialize(manager, value);
            XnaGameComponent component = value as XnaGameComponent;
            CodeStatementCollection statements = new CodeStatementCollection();
            if (component != null)
            {
                statements.Add(new CodeCommentStatement(""));
                statements.Add(new CodeCommentStatement(" " + component.Site.Name));
                statements.Add(new CodeCommentStatement(""));
                //Initialisation de la variable component1
                statements.Add(new CodeVariableDeclarationStatement(
                    component.GetType(),
                    component.Site.Name,
                    new CodeObjectCreateExpression(component.GetType(), new CodeExpression[] { })));

                statements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(
                        new CodeVariableReferenceExpression(component.Site.Name),
                        "Parent"),
                    new CodeThisReferenceExpression()));

                if (component.Project != null)
                    SerializeProperty(manager, statements, component, TypeDescriptor.GetProperties(component)["Project"]);

                //Instanciation d'un gameComponent
                if (component.GameComponentType != null)
                {

                    statements.Add(new CodeAssignStatement(
                        new CodePropertyReferenceExpression(
                            new CodeVariableReferenceExpression(component.Site.Name), "Component"),
                        new CodeObjectCreateExpression(component.GameComponentType, new CodeExpression[] { new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "Game") })));

                    if(typeof(XnaGameComponents.IPositionnable).IsAssignableFrom(component.GameComponentType))
                        statements.Add(new CodeAssignStatement(
                            new CodePropertyReferenceExpression(
                                new CodeCastExpression(typeof(XnaGameComponents.IPositionnable),
                                    new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(component.Site.Name), "Component")),
                                    "Name"),
                            new CodePrimitiveExpression(component.Site.Name)));

                        if (component.Component != null)
                        {
                            CollectionCodeDomSerializer ccds = new CollectionCodeDomSerializer();
                            CodeStatementCollection csc = (CodeStatementCollection)ccds.SerializeMemberAbsolute(manager, component,TypeDescriptor.GetProperties(component)["Component"]);
                            foreach (CodeStatement cs in csc)
                            {
                                if (cs is CodeAssignStatement)
                                {
                                    CodeAssignStatement cas = (CodeAssignStatement)cs;
                                    if (cas.Left is CodePropertyReferenceExpression)
                                    {
                                        CodePropertyReferenceExpression cpre = (CodePropertyReferenceExpression)cas.Left;
                                        if (cpre.TargetObject is CodePropertyReferenceExpression)
                                        {
                                            cpre = (CodePropertyReferenceExpression)cpre.TargetObject;
                                            if (cpre.PropertyName == "Component")
                                                ((CodePropertyReferenceExpression)cas.Left).TargetObject = new CodeCastExpression(component.GameComponentType, cpre);
                                        }
                                    }
                                }
                                if (cs is CodeExpressionStatement)
                                {
                                    if (((CodeExpressionStatement)cs).Expression is CodeMethodInvokeExpression)
                                    {
                                        CodeMethodInvokeExpression cmie = (CodeMethodInvokeExpression)((CodeExpressionStatement)cs).Expression;
                                        if (cmie.Method.TargetObject is CodePropertyReferenceExpression)
                                        {
                                            CodePropertyReferenceExpression cpre = (CodePropertyReferenceExpression)cmie.Method.TargetObject;
                                            if (cpre.TargetObject is CodePropertyReferenceExpression)
                                            {
                                                cpre = (CodePropertyReferenceExpression)cpre.TargetObject;
                                                if (cpre.PropertyName == "Component")
                                                    ((CodePropertyReferenceExpression)cmie.Method.TargetObject).TargetObject = new CodeCastExpression(component.GameComponentType, cpre);
                                            }
                                        }
                                    }
                                }
                            }
                            statements.AddRange(csc);
                        }
                }
            }
            return statements;
        }
    }

}
